using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging;
using MinoChat.Enums;
using MinoChat.Messages;
using MinoChat.Provider.Models;
using MinoChat.Provider.Services.Interfaces;
using MinoChat.Services.Interfaces;
using System.Collections.ObjectModel;
using System.Windows;

namespace MinoChat.ViewModels.Pages;

public partial class SettingsPageViewModel : ObservableObject
{
    private readonly ILogger<SettingsPageViewModel> _logger;
    private readonly IThemeService _themeService;
    private readonly INavigationService _navigationService;
    private readonly IProviderConfigService _providerConfigService;
    private readonly IUserInputService _userInputService;
    private readonly MinoChat.Ui.Services.SnackbarService _snackbarService;
    private ProviderConfig? _currentConfiguration;
    #region 属性
    [ObservableProperty]
    private string _selectedTheme = "浅色";
    [ObservableProperty]
    private ObservableCollection<string> _configFiles = new();
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(CanDeleteConfig))]
    private string _selectedConfigFile = "default";
    // 提供商表单属性
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(IsCompatibleProvider))]
    private string _currentProviderType = "OpenAI";
    [ObservableProperty]
    private string _currentProviderApiKey = string.Empty;
    [ObservableProperty]
    private string _currentProviderBaseUrl = string.Empty;
    // 模型ID（逗号分隔）
    [ObservableProperty]
    private string _currentModelIds = string.Empty;
    public ObservableCollection<string> AvailableThemes { get; } = new()
    {
        "浅色",
        "深色",
        "跟随系统"
    };
    public ObservableCollection<string> AvailableProviderTypes { get; } = new()
    {
        "OpenAI",
        "OpenAICompatible",
        "Anthropic",
        "AnthropicCompatible"
    };
    // 绑定IsEnabled属性，只有服务供应商为兼容模式才允许用户输入baseurl
    public bool IsCompatibleProvider => CurrentProviderType == "OpenAICompatible" || CurrentProviderType == "AnthropicCompatible";
    //删除按钮是否可点击(只有当前配置文件不为空且不是默认default才允许用户删除按钮)
    public bool CanDeleteConfig => !string.IsNullOrEmpty(SelectedConfigFile) &&
                                    !SelectedConfigFile.Equals("default", StringComparison.OrdinalIgnoreCase);
    #endregion

    public SettingsPageViewModel( ILogger<SettingsPageViewModel> logger, IThemeService themeService,
        INavigationService navigationService, IProviderConfigService providerConfigService,
        IUserInputService userInputService, MinoChat.Ui.Services.SnackbarService snackbarService)
    {
        _logger = logger;
        _themeService = themeService;
        _navigationService = navigationService;
        _providerConfigService = providerConfigService;
        _userInputService = userInputService;
        _snackbarService = snackbarService;
        // 从服务获取当前主题并设置到UI
        var currentMode = _themeService.GetCurrentThemeMode();
        SelectedTheme = _themeService.ConvertThemeModeToString(currentMode);
        // 加载配置文件列表
        Task.Run(async () =>
        {
            try
            {
                await LoadConfigFilesAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "初始化加载配置文件列表失败");
            }
        });
    }

    #region 配置文件管理
    //【1】加载配置目录Data/Provider下的json文件
    // 根据appsetting.json的配置项选中当前要加载的配置文件
    private async Task LoadConfigFilesAsync()
    {
        try
        {
            // 【1】确保默认配置存在(如果Data/Provides目录下不存在default.json就从程序嵌入资源中取出来)
            await _providerConfigService.EnsureDefaultConfigExistsAsync();
            // 【2】加载配置文件列表
            var files = await _providerConfigService.GetAllConfigFilesAsync();
            ConfigFiles.Clear();
            foreach (var file in files)
            {
                ConfigFiles.Add(file);
            }
            // 设置当前配置文件名称，如果查询不到取配置文件列表的第一个
            var currentConfig = _providerConfigService.GetCurrentConfigFileName();
            if (ConfigFiles.Contains(currentConfig))
            {    
                //绑定到前台属性
                SelectedConfigFile = currentConfig;
            }
            else if (ConfigFiles.Count > 0)
            {
                SelectedConfigFile = ConfigFiles[0];
            }
            // 强制加载当前选中的配置，确保表单显示数据
            if (!string.IsNullOrEmpty(SelectedConfigFile))
            {   
                // 加载配置文件中定义的模型
                await LoadConfigurationAsync(SelectedConfigFile);
            }
            _logger.LogInformation("成功加载{Count}个配置文件", ConfigFiles.Count);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "加载配置文件列表失败");
        }
    }
    // 【2】将json文件映射为ProviderConfig类
    private async Task LoadConfigurationAsync(string configName)
    {
        try
        {
            var config = await _providerConfigService.LoadConfigurationAsync(configName);
            if (config != null)
            {
                _currentConfiguration = config;
                // 加载配置到表单
                CurrentProviderType = config.Type.ToString();
                CurrentProviderApiKey = config.ApiKey ?? string.Empty;
                CurrentProviderBaseUrl = config.BaseUrl ?? string.Empty;
                CurrentModelIds = config.ModelIds ?? string.Empty;
                _logger.LogInformation("成功加载配置文件: {ConfigName}, 类型: {ImageType}, 模型: {ModelIds}",
                    configName, config.Type, config.ModelIds);
            }
            else
            {
                _logger.LogWarning("配置文件为空: {ConfigName}, 使用默认值", configName);
                // 设置默认值
                CurrentProviderType = "OpenAI";
                CurrentProviderApiKey = string.Empty;
                CurrentProviderBaseUrl = string.Empty;
                CurrentModelIds = string.Empty;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "加载配置失败: {ConfigName}", configName);
            // 出错时也设置默认值，避免表单显示旧数据
            CurrentProviderType = "OpenAI";
            CurrentProviderApiKey = string.Empty;
            CurrentProviderBaseUrl = string.Empty;
            CurrentModelIds = string.Empty;
        }
    }

    // 【3】切换配置文件写入appsetting并重新加载AI客户端(用户切换配置文件/新建配置文件时候调用)
    private async Task SwitchConfigurationAsync(string configName)
    {
        try
        {
            // 设置为当前配置并保存到appsettings.json
            await _providerConfigService.SetCurrentConfigFileNameAsync(configName);
            // 【重点】给ChatPage页面发送配置切换消息，通知AI服务重新加载模型
            WeakReferenceMessenger.Default.Send(new ProviderConfigChangedMessage(configName));
            _logger.LogInformation("已切换配置文件并发送重新加载消息: {ConfigName}", configName);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "切换配置文件失败: {ConfigName}", configName);
        }
    }
    //【4】用户切换配置文件的时候，从配置文件加载设置
    // 直接在UI线程上执行异步操作，会更新 UI 绑定的属性
    async partial void OnSelectedConfigFileChanged(string value)
    {
        if (!string.IsNullOrEmpty(value))
        {
            try
            {
                await LoadConfigurationAsync(value);
                await SwitchConfigurationAsync(value);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "切换配置文件时发生错误: {ConfigName}", value);
            }
        }
    }
    [RelayCommand]
    private async Task CreateConfig()
    {
        try
        {
            // 弹出输入配置文件名称对话框
            var newName = _userInputService.RequestInput("请输入配置文件名称：", "新建配置文件");
            if (string.IsNullOrWhiteSpace(newName))
                return;
            // 检查是否已存在
            if (ConfigFiles.Contains(newName))
            {
                MessageBox.Show($"配置文件 '{newName}' 已存在", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            // 创建新配置文件
            var newConfig = await _providerConfigService.CreateNewConfigAsync(newName);
            // 添加到列表
            ConfigFiles.Add(newName);
            // 切换到新配置（这会触发 OnSelectedConfigFileChanged，自动加载配置内容并设置为当前配置）
            SelectedConfigFile = newName;
            _logger.LogInformation("成功创建并切换到新配置: {ConfigName}", newName);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "创建配置文件失败");
            MessageBox.Show($"创建配置文件失败：{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }
    [RelayCommand]
    private async Task DeleteConfig()
    {
        if (!CanDeleteConfig)
            return;
        try
        {
            var result = MessageBox.Show(
                $"确定要删除配置文件 '{SelectedConfigFile}' 吗？",
                "确认删除",
                MessageBoxButton.YesNo,
                MessageBoxImage.Question);
            if (result == MessageBoxResult.Yes)
            {   
                // 删除选中的配置文件后，自动从列表里面选择第一个，并更新appsetting.json里面的配置
                await _providerConfigService.DeleteConfigAsync(SelectedConfigFile);
                // 根据appsetting.json里面的配置加载配置文件，初始化模型 
                await LoadConfigFilesAsync();
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "删除配置文件失败");
            MessageBox.Show($"删除配置文件失败：{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }
    //暂时保留按钮
    [RelayCommand]
    private async Task RefreshConfigs()
    {
        await LoadConfigFilesAsync();
    }
    #endregion

    #region 提供商管理
    // 绑定到保存按钮
    [RelayCommand]
    private async Task AddProvider()
    {
        // 验证输入
        if (string.IsNullOrWhiteSpace(CurrentProviderApiKey))
        {
            _snackbarService.Show("提示", "请输入 API Key", MinoChat.Ui.Enums.ImageType.Warning);
            return;
        }
        // 兼容服务需要 BaseUrl
        if (IsCompatibleProvider && string.IsNullOrWhiteSpace(CurrentProviderBaseUrl))
        {
            _snackbarService.Show("提示", "兼容服务需要填写 Base URL", MinoChat.Ui.Enums.ImageType.Warning);
            return;
        }
        // 非兼容服务不允许 BaseUrl
        if (!IsCompatibleProvider && !string.IsNullOrWhiteSpace(CurrentProviderBaseUrl))
        {
            _snackbarService.Show("提示", "官方服务不需要填写 Base URL", MinoChat.Ui.Enums.ImageType.Warning);
            return;
        }
        if (string.IsNullOrWhiteSpace(CurrentModelIds))
        {
            _snackbarService.Show("提示", "请输入模型ID（多个用逗号分隔）", MinoChat.Ui.Enums.ImageType.Warning);
            return;
        }
        try
        {
            // 创建配置对象
            var newConfig = new ProviderConfig
            {
                Type = Enum.Parse<ProviderType>(CurrentProviderType),
                ApiKey = CurrentProviderApiKey.Trim(),
                BaseUrl = IsCompatibleProvider ? CurrentProviderBaseUrl.Trim() : null,
                ModelIds = CurrentModelIds.Trim(),
                IsEnabled = true
            };
            // 验证配置
            var validationError = await _providerConfigService.ValidateProviderConfigAsync(newConfig);
            if (validationError != null)
            {
                _snackbarService.Show("错误", $"配置验证失败：{validationError}", MinoChat.Ui.Enums.ImageType.Error);
                return;
            }
            // 保存配置
            await _providerConfigService.SaveConfigurationAsync(newConfig, SelectedConfigFile);
            await _providerConfigService.SetCurrentConfigFileNameAsync(SelectedConfigFile);
            // 发送配置切换消息
            WeakReferenceMessenger.Default.Send(new ProviderConfigChangedMessage(SelectedConfigFile));
            // 更新当前配置
            _currentConfiguration = newConfig;
            _snackbarService.Show("成功", "配置保存成功！", MinoChat.Ui.Enums.ImageType.Success);
            _logger.LogInformation("保存配置成功: {ConfigName}, 类型: {ImageType}, 模型: {ModelIds}",
                SelectedConfigFile, newConfig.Type, newConfig.ModelIds);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "保存配置失败");
            _snackbarService.Show("错误", $"保存配置失败：{ex.Message}", MinoChat.Ui.Enums.ImageType.Error);
        }
    }
    #endregion
    #region 其他方法
    partial void OnSelectedThemeChanged(string value)
    {
        // 当主题选择变化时，立即应用主题
        var themeMode = _themeService.ConvertStringToThemeMode(value);
        _themeService.ApplyTheme(themeMode);
    }
    [RelayCommand]
    private void ClosePage()
    {
        _navigationService.GoBack();
    }
    #endregion
}
